#include <jni.h>
#include <string>
#include <cmath>
#include <cstdio>
#include <algorithm>

const jdouble PI = 3.1415926535897932;

extern "C" JNIEXPORT jstring JNICALL
Java_com_sjx_jnistudy_CalcUtils_getName(
        JNIEnv *env,
        jclass object) {
    std::string hello = "Hello from C++ getName";
    return env->NewStringUTF(hello.c_str());
}

extern "C" JNIEXPORT jbyteArray JNICALL Java_com_sjx_jnistudy_CalcUtils_getByteArray
        (JNIEnv *env, jclass object, jbyteArray j_array) {
    //1. 获取数组指针和长度
    jbyte *c_array = env->GetByteArrayElements(j_array, 0);
    int len_arr = env->GetArrayLength(j_array);
    //2. 具体处理
    jbyteArray c_result = env->NewByteArray(len_arr);
    jbyte buf[len_arr];
    for (int i = 0; i < len_arr; i++) {
        buf[i] = c_array[i] + 1;
    }
    //3. 释放内存
    env->ReleaseByteArrayElements(j_array, c_array, 0);
    //4. 赋值
    env->SetByteArrayRegion(c_result, 0, len_arr, buf);
    return c_result;
}

extern "C" JNIEXPORT jbyteArray JNICALL Java_com_sjx_jnistudy_CalcUtils_sinWave___3I_3IIII
        (JNIEnv *env, jclass object, jintArray freq, jintArray amplitude, jint sampleRate, jint updatePriodMs, jint maxProgress){
    // 获取数据指针
    jint *c_freq = env->GetIntArrayElements(freq, 0);
    jint *c_amplitude = env->GetIntArrayElements(amplitude, 0);
    // 获取长度
    int freqLen = env->GetArrayLength(freq);
    jint len = sampleRate / 1000 * updatePriodMs;
    jdouble temp = 2 * PI / sampleRate;

    jbyteArray c_result = env->NewByteArray(len);
    jdouble ds[len];
    jbyte bs[len];
    memset(ds, 0, sizeof(ds));
    memset(bs, 0, sizeof(ds));
    for (int i = 0; i < freqLen; i++){
        for (int j = 0; j < len; j++){
            ds[j] += c_amplitude[i] * sin(temp * j * c_freq[i]);
        }
    }
    // 找最大值 最小值
    jdouble maxD = 0;
    jdouble minD = 0;
    for(int i=0; i<len; i++){
        if(ds[i] > maxD) {
            maxD = ds[i];
        }
        if(ds[i] < minD){
            minD = ds[i];
        }
    }
    jdouble max = maxD > (minD * -1) ? maxD : (minD * -1);

    // 找幅度最大值
    jint listProgressMax = 0;
    for(int i=0; i<freqLen; i++){
        if(c_amplitude[i] > listProgressMax) listProgressMax = c_amplitude[i];
    }
    jdouble p = listProgressMax * 1.0 / maxProgress * 127 / max;
    for (int i = 0; i < len; i++){
        bs[i] = static_cast<jbyte>(ds[i] * p);
    }
    //3. 释放内存
    env->ReleaseIntArrayElements(freq, c_freq, 0);
    env->ReleaseIntArrayElements(amplitude, c_amplitude, 0);
    //4. 赋值
    env->SetByteArrayRegion(c_result, 0, len, bs);
    return c_result;
}


extern "C" JNIEXPORT jbyteArray JNICALL Java_com_sjx_jnistudy_CalcUtils_sinWave___3I_3IIII_3B
        (JNIEnv *env, jclass object, jintArray freq, jintArray amplitude, jint sampleRate, jint updatePriodMs, jint maxProgress, jbyteArray result){
    // 获取数据指针
    jint *c_freq = env->GetIntArrayElements(freq, 0);
    jint *c_amplitude = env->GetIntArrayElements(amplitude, 0);
    // 获取长度
    int freqLen = env->GetArrayLength(freq);
    jint len = sampleRate / 1000 * updatePriodMs;
    jdouble temp = 2 * PI / sampleRate;
    jdouble ds[len];
    jbyte bs[len];
    memset(ds, 0, sizeof(ds));
    memset(bs, 0, sizeof(ds));
    for (int i = 0; i < freqLen; i++){
        for (int j = 0; j < len; j++){
            ds[j] += c_amplitude[i] * sin(temp * j * c_freq[i]);
        }
    }
    // 找最大值 最小值
    jdouble maxD = 0;
    jdouble minD = 0;
    for(int i=0; i<len; i++){
        if(ds[i] > maxD) {
            maxD = ds[i];
        }
        if(ds[i] < minD){
            minD = ds[i];
        }
    }
    jdouble max = maxD > (minD * -1) ? maxD : (minD * -1);

    // 找幅度最大值
    jint listProgressMax = 0;
    for(int i=0; i<freqLen; i++){
        if(c_amplitude[i] > listProgressMax) listProgressMax = c_amplitude[i];
    }
    jdouble p = listProgressMax * 1.0 / maxProgress * 127 / max;
    for (int i = 0; i < len; i++){
        bs[i] = static_cast<jbyte>(ds[i] * p);
    }
    //3. 释放内存
    env->ReleaseIntArrayElements(freq, c_freq, 0);
    env->ReleaseIntArrayElements(amplitude, c_amplitude, 0);
    //4. 赋值
    env->SetByteArrayRegion(result, 0, len, bs);
    return result;
}